#include "Http_Util.hpp"
#include "Http_Request.hpp"
#include <regex>

typedef enum
{
    RECV_HTTP_ERROR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
} HttpRecvStatu;

#define MAX_LINE 8192
class HttpContext
{
private:
    int _resp_statu;
    HttpRecvStatu _recv_statu; // 当前接收及解析的阶段状态
    HttpRequest _request;      // 已经解析得到的请求信息

private:
    // 行解析
    bool ParseHttpLine(const std::string &line)
    {
        std::regex re("(GET|HEAD|POST|PUT|DELETE) (([^?]+)(?:\\?(.*?))?) (HTTP/1\\.[01])(?:\r\n|\n)");
        std::smatch matches;
        bool ret = std::regex_match(line, matches, re);

        // 0 : GET /bitejiuyeke/login?user=xiaoming&pass=123123 HTTP/1.1
        // 1 : GET
        // 2 : /bitejiuyeke/login
        // 3 : user=xiaoming&pass=123123
        // 4 : HTTP/1.1
        // 请求的获取

        if (ret == false)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400;
            return false;
        }
        _request._method = matches[1];
        // 将字符转大写
        std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(), ::toupper);

        // 资源路径的获取需要进行URL解码操作
        _request._path = Util::UrlDecode(matches[2], false);

        _request._version = matches[4];

        // 查询字符串的获取与处理
        std::vector<std::string> query_string_arry;
        std::string query_string = matches[3];

        // 查询字符以&先以进行分割，中间再以字符=进行分割

        Util::Split(query_string, "&", &query_string_arry);

        for (auto &str : query_string_arry)
        {
            size_t pos = str.find("=");
            if (pos = std::string::npos)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 400;
                return false;
            }
            std::string key = Util::UrlDecode(str.substr(0, pos), true);
            std::string val = Util::UrlDecode(str.substr(pos + 1), true);

            _request.SetParam(key, val);
        }

        return true;
    }

    bool RecvHttpline(Buffer *buf)
    {
        if (_recv_statu != RECV_HTTP_LINE)
            return false;

        // 获取第一行的数据
        std::string line = buf->GetLineAndPop();

        if (line.size() == 0)
        {
            // 缓冲区的数据不足一行，但是已经很长了，这是有问题的
            if (buf->ReadAbleSize() > MAX_LINE)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414;
                return false;
            }
            return true;
        }

        if (line.size() > MAX_LINE)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 414;
            return false;
        }

        bool ret = ParseHttpLine(line);
        if (ret == false)
        {
            return false;
        }
        _recv_statu = RECV_HTTP_HEAD;
        return buf;
    }

    bool ParseHead(std::string &line)
    {
        if (line.back() == '\n')
            line.pop_back();
        if (line.back() == '\r')
            line.pop_back();

        size_t pos = line.find(":");
        if (pos == std::string::npos)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400;
            return false;
        }

        std::string key = line.substr(0, pos);
        std::string val = line.substr(pos + 2);
        _request.SetHeader(key, val);
        return true;
    }

    bool RecvHttpHead(Buffer *buf)
    {
        if (_recv_statu != RECV_HTTP_HEAD)
            return false;

        // 一行一行的取出数据直到为空行
        while (1)
        {
            std::string line = buf->GetLineAndPop();

            // 如果数据不足一行
            if (line.size() == 0)
            {
                if (buf->ReadAbleSize() > MAX_LINE)
                {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 414;
                    return false;
                }
                return true;
            }

            if (line.size() > MAX_LINE)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414;
                return false;
            }

            if (line == "\n" || line == "\r\n")
            {
                break;
            }
            bool ret = ParseHead(line);
            if (ret == false)
            {
                return false;
            }
        }

        _recv_statu = RECV_HTTP_BODY;
        return true;
    }

    bool RecvHttpBody(Buffer *buf)
    {
        if (_recv_statu != RECV_HTTP_BODY)
            return false;

        size_t content_length = _request.ContentLength();
        if (content_length == 0)
        {
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }

        // 实际还需要接收数据的长度
        size_t real_len = content_length - _request._body.size();

        // 数据足够，直接读取所有正文，取出数据
        if (buf->ReadAbleSize() > real_len)
        {
            _request._body.append(buf->ReaderPosition(), real_len);
            buf->MoveReadOffset(real_len);
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }

        // 数据不够，先读取，不改变读取状态，之后等待新数据到来
        _request._body.append(buf->ReaderPosition(), buf->ReadAbleSize());
        buf->MoveReadOffset(buf->ReadAbleSize());
        return true;
    }

public:
    HttpContext() : _resp_statu(200), _recv_statu(RECV_HTTP_LINE) {}

    void RSet()
    {
        _resp_statu = 200;
        _recv_statu = RECV_HTTP_LINE;
        _request.RSet();
    }

    int RespStaut()
    {
        return _resp_statu;
    }

    HttpRecvStatu RecvStaut()
    {
        return _recv_statu;
    }

    HttpRequest &Request()
    {
        return _request;
    }

    void RecvHttpRequest(Buffer *buf)
    {
        switch (_recv_statu)
        {
        case RECV_HTTP_LINE:
            RecvHttpline(buf);
        case RECV_HTTP_HEAD:
            RecvHttpHead(buf);
        case RECV_HTTP_BODY:
            RecvHttpBody(buf);
        }
        return;
    }

    
};